package com.bitejiuyeke.bitecommoncore.utils;

import com.bitejiuyeke.bitecommondomain.constants.CommonConstants;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import io.micrometer.common.util.StringUtils;


import java.text.SimpleDateFormat;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

public class JsonUtil {

    private JsonUtil(){

    }

    private static final ObjectMapper OBJECT_MAPPER;

    static {
        OBJECT_MAPPER =
                JsonMapper.builder().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                        .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
                        .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
                        .configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false)
                        .configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS,
                                false)
                        .configure(MapperFeature.USE_ANNOTATIONS, false)
                        .addModule(new JavaTimeModule())
                        .defaultDateFormat(new
                                SimpleDateFormat(CommonConstants.STANDARD_FORMAT))
                        .serializationInclusion(JsonInclude.Include.NON_NULL)
                        .build();
    }


    public static ObjectMapper getObjectMapper(){
        return OBJECT_MAPPER;
    }

    private static  <T> T tryParse(Callable<T> parser)  {
        return tryParse(parser, JacksonException.class);
    }

    private static <T> T tryParse(Callable<T> parser, Class<? extends Exception> check)  {
        try {
            return parser.call();
        } catch (Exception var4) {
            if (check.isAssignableFrom(var4.getClass())) {
                try {
                    throw new JsonParseException(var4.getMessage());
                } catch (JsonParseException e) {
                    throw new RuntimeException(e);
                }
            }

            throw new IllegalStateException(var4);
        }
    }


    /**
     * 对象转字符串
     * @param obj
     * @return
     * @param <T>
     */
    public static <T> String obj2String(T obj){
        if(null==obj){
            return null;
        }
        return JsonUtil.tryParse(()->{
            return JsonUtil.getObjectMapper().writeValueAsString(obj);
        });
    }


    /**
     * 美化的对象转字符串
     * @param obj
     * @return
     * @param <T>
     */
    public static <T> String obj2StringPretty(T obj){
        if(null==obj){
            return null;
        }
        return JsonUtil.tryParse(()->{
            return JsonUtil.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        });
    }


    /**
     * 字符串转自定义对象
     * @param str
     * @param clazz
     * @return
     * @param <T>
     */
    public static <T> T string2Obj(String str,Class<T> clazz){

        if(null==str||(StringUtils.isEmpty(str)|| clazz==null)) return null;

        return String.class.equals(clazz)?(T)str
                :tryParse(()->{
            return JsonUtil.getObjectMapper().readValue(str,clazz);
        });

    }

    /**
     * 字符串转嵌套对象
     * @param str
     * @param valueTypeRef
     * @return
     * @param <T>
     */

    public static <T> T string2Obj(String str, TypeReference<T> valueTypeRef){
        if(null==str || (StringUtils.isEmpty(str) || valueTypeRef==null)) return null;

        return JsonUtil.tryParse(()->{
            return JsonUtil.getObjectMapper().readValue(str,valueTypeRef);
        });

    }


    /**
     * 字符串转List
     * @param str
     * @param clazz
     * @return
     * @param <T>
     */

    public static <T> List<T> string2List(String str, Class<T> clazz){

        if(null==str||(StringUtils.isEmpty(str)|| clazz==null)) return null;

        JavaType javaType= JsonUtil.getObjectMapper().getTypeFactory().constructParametricType(List.class,clazz);

        return tryParse(()->{
            return JsonUtil.getObjectMapper().readValue(str,javaType);
        });
    }


    /**
     * 字符串转Map
     * @param str
     * @param valueClass
     * @return
     * @param <T>
     */


    public static <T> Map<String, T> string2Map(String str, Class<T>
            valueClass){
        if (str == null || str.isEmpty() || valueClass == null) {
            return null;
        }
        JavaType javaType =
                JsonUtil.getObjectMapper().getTypeFactory().constructMapType(LinkedHashMap.class,
                        String.class, valueClass);

            return JsonUtil.tryParse(()->{
                return JsonUtil.getObjectMapper().readValue(str, javaType);
        });
    }











}
